package org.atlantis.grosbeak.pot;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.atlantis.grosbeak.lang.Exceptions;

/**
 * Pot的工具类。PotKit类中的所有方法均为静态方法，不需要（而且也不能）实例化PotKit类，直接使用即可。 用户一般不需要使用到此类。
 * 
 * @author <a href="mailto:seenoevil.cn@gmail.com">SeeNoEvil</a>
 * 
 */
public abstract class PotKit {

	/**
	 * 将一段SQL转换成预处理的SQL。如：
	 * <ul>
	 * <li>
	 * PotKit.getPreparedSql("SELECT * FROM demos WHERE id = :id")的结果是：SELECT *
	 * FROM demos WHERE id = ?</li>
	 * <li>PotKit.getPreparedSql(
	 * "INSER INTO demos(author, content) values(:author, :content)")的结果是：INSER
	 * INTO demos(author, content) values(?, ?)</li>
	 * </ul>
	 * 
	 * @param sql
	 *            需要转换的SQL。
	 * @return 转换后的SQL。
	 */
	public static String getPreparedSql(String sql) {
		return sql.replaceAll(
				"(\\:[a-zA-Z0-9]+(\\.[a-zA-Z\\_]{1}[a-zA-Z0-9\\_]*)?)", "?");
	}

	/**
	 * 从一段SQL语句中获取需要注入到SQL的参数的参数名。如：
	 * 
	 * <pre>
	 * PotKit.getParamNames("INSER INTO demos(author, content) values(:author, :content)")得到
	 * 的结果就是：["author", "content"]
	 * </pre>
	 * 
	 * @param sql
	 * @return 所有参数名的数组。
	 */
	public static String[] getParamNames(String sql) {
		List<String> list = new ArrayList<String>();
		int fromIndex = 0;
		while (true) {
			int pos = sql.indexOf(':', fromIndex);
			if (pos == -1)
				break;
			String name = getParamName(sql, pos);
			fromIndex = pos + 1 + name.length();
			list.add(name);
		}
		return list.toArray(new String[list.size()]);
	}

	/**
	 * 从一段SQL语句中，和给定的字符位置查找一个参数名。
	 * 
	 * @param sql
	 * @param pos
	 * @return
	 */
	public static String getParamName(String sql, int pos) {
		StringBuilder name = new StringBuilder(8);
		for (int i = pos + 1; i < sql.length(); i++) {
			char c = sql.charAt(i);
			if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')
					|| (c >= 'A' && c <= 'Z') || c == '.' || c == '_') {
				name.append(c);
			} else {
				break;
			}
		}
		if (name.length() == 0)
			throw Exceptions.makeThrow(PotException.class,
					"Bad parameter ':' symbol in SQL:[%s], position:[%d]", sql,
					pos);
		String result = name.toString();
		if (!result.matches("[0-9a-zA-Z]+(\\.[a-zA-Z\\_]{1}[a-zA-Z0-9\\_]*)?"))
			throw Exceptions.makeThrow(PotException.class,
					"Bad parameter [:%s] in SQL:[%s], position:[%d]", result,
					sql, pos);
		return result;
	}

	/**
	 * 获得一个RowMapper实现类的泛型的类型。如：
	 * 
	 * <pre>
	 * class DemoRowMapper extends RowMapper<Integer> {
	 * 		...
	 * }
	 * 那么PotKit.getRowMapperGenericType(DemoRowMapper.class);得到的结果就是Integer.class。
	 * </pre>
	 * 
	 * @param clazz
	 *            RowMapper实现类的Class。
	 * @return 泛型的类型。
	 */
	public static Class<?> getRowMapperGenericType(Class<?> clazz) {
		Type type = clazz.getGenericSuperclass();
		if (type == null || (type instanceof Class<?>))
			return Object.class;
		ParameterizedType pt = (ParameterizedType) type;
		type = pt.getActualTypeArguments()[0];
		if (type instanceof GenericArrayType) {
			type = ((GenericArrayType) type).getGenericComponentType();
			return Array.newInstance((Class<?>) type, 0).getClass();
		}
		if (type instanceof ParameterizedType) {
			pt = (ParameterizedType) type;
			type = pt.getRawType();
		}
		return (Class<?>) type;
	}

	/**
	 * 给一个PreparedStatement对象绑定参数。
	 * 
	 * @param pstmt
	 *            需要进行参数绑定的PreparedStatement对象。
	 * @param params
	 *            需要进行绑定的参数。
	 * @throws SQLException
	 */
	public static void bindParams(PreparedStatement pstmt, Object... params)
			throws SQLException {
		for (int i = 0; i < params.length; i++) {
			pstmt.setObject(i + 1, params[i]);
		}
	}

	/**
	 * 生成一个UUID编号。
	 * 
	 * @return UUID编号的字符串形式。
	 */
	public static String generateUUID() {
		return UUID.randomUUID().toString().replace("-", "");
	}

	/**
	 * 安全的关闭（即不抛出异常的关闭）一个Statement对象。
	 * 
	 * @param stmt
	 *            需要关闭的Statement对象。
	 */
	public static void safelyClose(Statement stmt) {
		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
			}
		}
	}

	/**
	 * 安全的关闭（即不抛出异常的关闭）一个ResultSet对象。
	 * 
	 * @param rs
	 *            需要关闭的ResultSet对象。
	 */
	public static void safelyClose(ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
			}
		}
	}
}
